package OperationSystem.day1206.OutputStream.spy;

import java.io.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Copy_All_Directory {//复制路径下的所有文件

    private static class CopyFileTask implements Runnable {//创建
        private final String srcPath;
        private final String destPath;

        CopyFileTask(String srcPath, String destPath) {
            this.srcPath = srcPath;
            this.destPath = destPath;
        }

        @Override
        public void run() {
            try {
                copyFile(srcPath, destPath);
                System.out.println(destPath + "文件复制成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static String srcAbsPath;
    private static String destAbsPath;
    private static ExecutorService threadPool;//创建一个线程池

    public static void main(String[] args) throws IOException {
        if (args.length < 2) {
            System.out.println("请按照以下格式使用程序");
            System.out.println("CopyDirectory 源目录 目标目录");
            return;
        }

        //提交一个线程池,设置最大线程数为50
        threadPool = Executors.newFixedThreadPool(50);

        //String srcPath = "";
        //String destPath = "";
        String srcPath = args[0];
        String destPath = args[1];
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);

        srcAbsPath = srcFile.getAbsolutePath();
        destAbsPath = destFile.getAbsolutePath();

        //TODO:检查源文件是否存在，存在的话是否是目录
        //TODO：检查目标文件是否不存在
        //TODO：检查目标文件的上一级目录是否存在

        copyDirectory(srcPath, destPath);

        threadPool.shutdown();
    }

    /**
     * 思路：遍历所有的目录结构
     * 如果是目录，我也创建目录
     * 如果是文件，调用复制文件的方式进行复制
     *
     * @param srcPath  源文件目录
     * @param destPath 目标文件目录
     * @throws IOException
     */

    private static void copyDirectory(String srcPath, String destPath) throws IOException {//执行复制
        File file = new File(srcPath);
        traversalDirectory(file);
    }

    //↓复制目录只需要复制srcPath的相对路径
    private static void doDirectory(File directory) {//复制目录时，创建目录的方法
        //为了找出要复制的目录的相对路径---（相对于原路径-----根）
        String srcPath = directory.getAbsolutePath();
        String relativePath = srcPath.substring(srcAbsPath.length());
        String destPath = destAbsPath + relativePath;

        File destDirectory = new File(destPath);
        destDirectory.mkdir();//因为数从根往下遍历的，所以上一级的目录，一定已经被创建了
        System.out.println(destPath + "目录创建成功");
    }

    private static void doFile(File file) throws IOException {//复制时，处理文件的方法
        //找路径方法和上面方法相同
        String srcPath = file.getAbsolutePath();
        String relativePath = srcPath.substring(srcAbsPath.length());
        String destPath = destAbsPath + relativePath;

        threadPool.execute(new CopyFileTask(srcPath, destPath));
        /**copyFile(file.getAbsolutePath(), destPath);
         *System.out.println(destPath + "文件复制成功");
         */
    }

    //↑复制文件直接使用前几节课的复制文件
    //正常使用的话，肯定是拷贝文件最慢
    //这是就可以使用多线程来优化速度问题
    private static void copyFile(String srcPath, String destPath) throws IOException {//复制文件
        try (InputStream is = new FileInputStream(srcPath)) {
            try (OutputStream os = new FileOutputStream(destPath)) {
                byte[] buffer = new byte[4096];
                int len;
                while ((len = is.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
                os.flush();
            }
        }
    }

    private static void doNode(File node) throws IOException {//根据节点是目录还是普通文件，选择处理的方法
        if (node.isDirectory()) {
            doDirectory(node);
        } else {
            doFile(node);
        }
    }

    private static void traversalDirectory(File root) throws IOException {//深度遍历遍历文件
        doNode(root);//被遍历到的每个节点，都需要被调用

        if (root.isDirectory()) {
            File[] files = root.listFiles();
            if (files != null) {
                for (File file : files) {
                    traversalDirectory(file);
                }
            }
        }
    }
}
